<?php

namespace interface\v1;

/*
*考勤接口类
*/

class clockAppClass extends index
{
	private const page  = 'workSignCheck';
	private const table = 'work_sign';
	public array $weekArray = array("日", "一", "二", "三", "四", "五", "六");
	public int   $rangeHour = 3;//小时，获取打卡记录的范围，
	
	/**
	 * 根据坐标解析出地址
	 *
	 * @param $lat
	 * @param $lng
	 * @return array
	 */
	public static function coordinateToAddr($lat, $lng): array
	{
		$key          = para('tencentMapKey');
		$res          = self::curlGet("https://apis.map.qq.com/ws/geocoder/v1/?location=" . $lat . ',' . $lng . "&key={$key}");
		$res          = json_decode($res, true);
		$json['data'] = [];
		$json['warn'] = 'ok';
		if ($res['status'] == 0) {
			$json['data']     = $res['result'];
			$json['err_code'] = 0;
		} else {
			$json['err_code'] = 1;
			$json['warn']     = '请求数据失败：' . json_encode($res, 320);
		}
		return $json;
	}
	
	/*查询条件*/
	public function clockPage()
	{
		$lat = $this->post('lat');
		$lng = $this->post('lng');
		if (empty($lat) || empty($lng)) {
			$this->resp['warn'] = '未获取到当前经纬度';
		} else {
			$this->code = 1;
			$clockRule  = query('clock_rule', " member like '%" . self::$stid . "%' and state = '启用' and UNIX_TIMESTAMP(startTime) <=UNIX_TIMESTAMP() order by startTime desc");
			$address    = self::coordinateToAddr($lat, $lng);
			//判断当天的打卡条数
			$clockRecordNum = self::total(array('table' => self::table, 'where' => "stid = '" . self::$stid . "' and date(signTime) = '" . $this->date . "'"));
			if ($clockRecordNum == 0) {
				$clockType = 0;
			} elseif ($clockRecordNum == 1) {
				$clockType = 1;
			} else {
				$clockType = 2;
			}
			//上班
			$startSignTime = query(self::table, "stid = '" . self::$stid . "' and date(signTime) = '" . $this->date . "' order by signTime asc");
			//下班
			$endSignTime        = query(self::table, "stid = '" . self::$stid . "' and date(signTime) = '" . $this->date . "' order by signTime desc");
			$data['result']     = [
				'ico'           => self::fillSrc($this->control['ico'], $this->control['updateTime']),
				'name'          => $this->control['name'],
				'job'           => $this->controlJob['name'],
				'team'          => $clockRule['team'],
				'address'       => $address['data']['address_component']['city'] . $address['data']['formatted_addresses']['recommend'],
				'clockType'     => $clockType,//0:未打卡 1：上午已打卡 2：都已打卡
				'startSignTime' => $startSignTime['id'] ? date('H:i', strtotime($startSignTime['signTime'])) : '',
				'startSignId'   => $startSignTime['id'],
				'endSignTime'   => $endSignTime['id'] ? date('H:i', strtotime($endSignTime['signTime'])) : '',
				'endSignId'     => $endSignTime['id'],
			];
			$this->resp['data'] = $data;
		}
	}
	
	/**
	 * 打卡
	 */
	public function sign()
	{
		$lat = $this->post('lat');
		$lng = $this->post('lng');
		if (empty($lat) || empty($lng)) {
			$this->resp['warn'] = '未获取到当前经纬度';
		} else {
			$this->resp['warn'] = static::insert(array(
				'table' => self::table,
				'field' => [
					'jobId'    => $this->control['jobId'],
					'stid'     => self::$stid,
					'signTime' => $this->time,
					'type'     => '小程序',
					'latlng'   => $lat . ',' . $lng,
				],
			));
			if ($this->resp['warn'] == '新增成功') {
				$this->code                      = 1;
				$this->resp['warn']              = '打卡成功';
				$this->resp['data']['clockTime'] = date('H:i:s');
			} else {
				$this->resp['warn'] = '打卡失败';
			}
		}
	}
	
	/**
	 * 重新打卡
	 */
	public function reSign()
	{
		$id   = $this->post('id');
		$lat  = $this->post('lat');
		$lng  = $this->post('lng');
		$info = query(self::table, "id = '$id'");
		if (empty($id) || empty($info['id'])) {
			$this->resp['warn'] = '未找到打卡记录';
		} elseif ($info['stid'] != self::$stid) {
			$this->resp['warn'] = '这不是你的打卡记录';
		} elseif (empty($lat) || empty($lng)) {
			$this->resp['warn'] = '未获取到当前经纬度';
		} else {
			$warn = static::update(array(
				'table' => self::table,
				'field' => [
					'signTime' => $this->time,
					'type'     => '小程序',
					'latlng'   => $lat . ',' . $lng,
					'text'     => '小程序重新打卡',
				],
				'where' => "id = '$id'",
			));
			if ($warn == '更新成功') {
				$this->code         = 1;
				$this->resp['warn'] = '打卡成功';
			} else {
				$this->resp['warn'] = '打卡失败';
			}
		}
	}
	
	/**
	 * 统计
	 */
	public function statistics()
	{
		//数据查询
		$month = $this->post('month');//切换月份
		if ($month) {
			$date = $month . '-01';
		} else {
			$date = $this->post('date') ?: $this->date;
		}
		$this->code = 1;
		$month      = date('Y-m', strtotime($date));//月份
		$days       = date('t', strtotime($date));  //此月份总天数
		$dayArr     = [];
		$now_week   = date('w', strtotime(date('Y-m-01', strtotime($date))));
		for ($i = 0; $i < $now_week; $i++) {
			$dayArr[] = [
				'index'     => ' ',
				'state'     => ' ',
				'date'      => ' ',
				'isWorkDay' => ' ',
			];
		}
		for ($i = 1; $i <= $days; $i++) {
			$today    = $month . '-' . sprintf("%02d", $i);
			$result   = $this->workSignRecord($today);
			$dayArr[] = [
				'index'     => $i,
				'date'      => $today,
				'isWorkDay' => $this->isWorkDay($today) ? 1 : 0,
				'state'     => $result['state'],
			];
		}
		$result             = $this->workSignRecord($date);
		$data['result']     = [
			'date'          => $date,
			'month'         => $month,
			'formatDate'    => date('m月d日', strtotime($date)) . ' 周' . $this->weekArray[date("w", strtotime($date))] . ' ' . ($date == $this->date ? '(今天)' : ''),
			'startSignTime' => $result['startSignTime'],
			'endSignTime'   => $result['endSignTime'],
			'state'         => $result['state'] ?: '',
			'list'          => $dayArr,
		];
		$this->resp['data'] = $data;
	}
	
	/**
	 * 查找
	 */
	public function searchRecord()
	{
		$date = $this->post('date');
		if (empty($date)) {
			$this->resp['warn'] = '请选择日期';
		} else {
			$this->code         = 1;
			$result             = $this->workSignRecord($date);
			$data['result']     = [
				'formatDate'    => date('m月d日', strtotime($date)) . ' ' . $this->weekArray[date("w", strtotime(date('Y-m', strtotime($date))))] . ' ' . ($date == $this->date ? '(今天)' : ''),
				'startSignTime' => $result['startSignTime'],
				'endSignTime'   => $result['endSignTime'],
				'state'         => $result['state'],
			];
			$this->resp['data'] = $data;
		}
	}
	
	/**
	 * 判断当前日期是否是工作日
	 *
	 * @param $date
	 * @return bool
	 */
	public function isWorkDay($date): bool
	{
		$staff = $this->control;
		//考勤规则
		$clockRule = query('clock_rule', " member like '%" . self::$stid . "%' and state = '启用' and UNIX_TIMESTAMP(startTime) <=UNIX_TIMESTAMP('{$date}') order by startTime desc");
		
		//本月工作日
		$workDayResult = $this->getWorkDay(date('Y-m', strtotime($date)), $clockRule['workDayId']);
		$workDay       = $workDayResult['workDay'];
		
		$isInSchedule = false;//是否在排班工作日期中
		if ($clockRule['type'] == 2) {
			//排班表
			$roster = query('roster', " clockRuleId = '$clockRule[id]'");
			//获取当天的排班
			$schedule = query('roster_schedule', " stid = '$staff[stid]' and toDay = '$date' and orderId = '$roster[id]'");
			if ($schedule['id'] && $schedule['rosterMxId'] != 'rest') {
				$isInSchedule = true;
			}
		}
		if ((in_array($date, (array)$workDay) && in_array($clockRule['type'], [1, 3])) || (in_array($date, (array)$workDay) && $clockRule['type'] == 2 && $isInSchedule)) {
			return true;
		}
		return false;
	}
	
	/**
	 * 获取可用的打卡记录
	 *
	 * @param $date
	 */
	public function workSignRecord($date): array
	{
		$rangHour          = 3;
		$absenteeismMinute = para('absenteeismMinute');
		$staff             = $this->control;
		$staffEntryRecord  = query('staff_entry_record', "talentId = '$staff[talentId]' and state = '已通过' order by entryDate desc,time desc");
		$staff['entryDay'] = $staffEntryRecord['entryDate'];
		//考勤规则
		$clockRule = query('clock_rule', " member like '%" . self::$stid . "%' and state = '启用' and UNIX_TIMESTAMP(startTime) <=UNIX_TIMESTAMP('{$date}') order by startTime desc");
		
		//本月工作日
		$workDayResult = $this->getWorkDay(date('Y-m', strtotime($date)), $clockRule['workDayId']);
		$workDay       = $workDayResult['workDay'];
		
		$isInSchedule = false;//是否在排班工作日期中
		$schedule     = [];   //排班班次
		if ($clockRule['type'] == 2) {
			//排班表
			$roster = query('roster', " clockRuleId = '$clockRule[id]'");
			//获取当天的排班
			$schedule = query('roster_schedule', " stid = '$staff[stid]' and toDay = '$date' and orderId = '$roster[id]'");
			if ($schedule['id'] && $schedule['rosterMxId'] != 'rest') {
				$isInSchedule = true;
			}
		}
		if ((in_array($date, (array)$workDay) && (strtotime($date) <= time()) && in_array($clockRule['type'], [1, 3])) || (in_array($date, (array)$workDay) && $clockRule['type'] == 2 && $isInSchedule)) {
			//查询是否为工作日
			$state           = '';
			$signStartResult = $signEndResult = '-';
			$todayStart      = $date . " 00:00:00";
			$todayEnd        = $date . " 23:59:59";
			$sign            = $this->workSign(1, $staff['stid'], $todayStart, $todayEnd);
			//当日加班记录  开始时间在当天的加班记录
			$sql = find(array("table" => "work_add", "where" => " stid = '$staff[stid]' and date(timeStart) = '$date' and state = '已通过' order by time "));
			foreach ($sql['array'] as $array) {
				if ($array['timeStart'] < $todayEnd and $todayEnd < $array['timeEnd']) {//如果加班超过凌晨
					$sign["23:59:59"] = array("type" => "加", "text" => $array['result']);
				}
			}
			if ($clockRule['type'] == 1) {
				//按固定时间上下班
				$clockTimeMx      = find(array('table' => 'clock_rule_time', 'where' => " orderId = '$clockRule[id]' order by list asc"));
				$endClockTime     = end($clockTimeMx['array']);
				$morning['start'] = strtotime($date . " " . $clockTimeMx['array'][0]['startTime']);//上午上班时间戳
				//判断下班时间是否是次日
				if ($endClockTime['endType'] == 1) {
					//次日
					$nextDay          = date('Y-m-d', strtotime("+1", strtotime($date)));
					$afternoon['end'] = strtotime($nextDay . " " . $endClockTime['endTime']);//下午下班时间戳
				} else {
					$afternoon['end'] = strtotime($date . " " . $endClockTime['endTime']);//下午下班时间戳
				}
				
				//过滤上午上班两小时前的签到，可能为上一天的加班打卡
				foreach ($sign as $key => $value) {
					$signStamp = strtotime($key);//签到时间戳
					if ($signStamp < $morning['start'] - 3600 * $rangHour) {
						unset($sign[$key]);
					}
				}
				//打卡时间顺序排列
				ksort($sign);
				$signNum = count($sign);//今天打卡的次数
				$holiday = $this->judgeOneDayLeave($staff['stid'], $date, $clockTimeMx['array']);
				
				if ($holiday['oneDay']) {
					//全天请假
					$state = '请假';
				} elseif (strtotime($date) >= time()) {//未来时间
					$state = "---";
				} elseif (strtotime($date) < strtotime($staff['entryDay'])) {//今天未入职
					$state = "未入职";
				} elseif ($staff['state'] == "离职" and strtotime($staff['quitDay']) < strtotime($date)) {//今天已离职
					$state = "已离职";
				} elseif ($signNum == 0) {
					$state = '旷工';
				} elseif ($signNum == 1) {
					$state     = '旷工';
					$signTime  = key($sign);          //唯一打卡时间
					$signStamp = strtotime($signTime);//签到时间戳
					$text      = date("H:i:s", strtotime($signTime));
					if ($afternoon['end'] <= $signStamp) {//如果是下班之后打的卡
						$signStartResult = '缺卡';
						$signEndResult   = $text;
					} elseif ($signStamp <= $morning['start']) {//如果是上班之前打的卡
						$signStartResult = $text;
						$signEndResult   = '缺卡';
					} elseif ($signStamp <= $morning['start'] + 60 * $absenteeismMinute) {
						//迟到半小时内
						$signStartResult = $text;
						$signEndResult   = '缺卡';
					} else {
						//迟到半小时后
						$signStartResult = $text;
						$signEndResult   = '缺卡';
					}
				} else {
					$state          = '正常';
					$signStartTime  = key($sign);
					$signStartStamp = strtotime($signStartTime);
					//下班签到时间戳
					end($sign);//把指针切换到数组最后一条记录
					$signEndTime  = key($sign);
					$signEndStamp = strtotime($signEndTime);
					//判断
					if ($signEndStamp <= $morning['start']) {//仅在上班前打了两次卡
						$signStartResult = date("H:i:s", strtotime($signStartTime));
						$signEndResult   = '缺卡';
						$state           = '旷工';
					} elseif ($afternoon['end'] <= $signStartStamp) {//仅在下班后打了两次卡
						$signStartResult = '缺卡';
						$signEndResult   = date("H:i:s", strtotime($signEndTime));
						$state           = '旷工';
					} else {
						//两次打卡都在上班时间或正常打卡
						$isOneDayWork = true;                                   //判断是否为非旷工的标志
						//上班签到标记
						$signStartResult = date("H:i:s", strtotime($signStartTime));
						if ($signStartStamp > $morning['start']) {
							//有迟到
							//上班签到前缺勤分钟数
							$leaveStart = $this->calculateRemindEarlyHour($date, $signStartStamp, $clockTimeMx['array']);
							//上班签到前的总请假分钟数
							$holidayStart = $this->calculateEarlyHolidayHour($staff['stid'], $date, $signStartStamp, $clockTimeMx['array']);
							
							if (($leaveStart - $holidayStart) <= $absenteeismMinute) {
								//缺勤分钟数扣除请假分钟数后如果在<=半小时，则属于迟到
								$state = '迟到';
							} elseif ($leaveStart > $holidayStart) {
								//如果有旷工
								$isOneDayWork = false;
							}
						}
						//下班签到标记
						$signEndResult = date("H:i:s", strtotime($signEndTime));//下班签到标记
						if ($afternoon['end'] > $signEndStamp) {
							//有早退
							//当前打卡时间后的缺勤分钟数
							$no_work_minute = $this->calculateRemindWorkHour($date, $signEndStamp, $clockTimeMx['array']);
							//当前打卡时间后的请假分钟数
							$holidayMinute = $this->calculateHolidayHour($staff['stid'], $date, $signEndStamp, $clockTimeMx['array']);
							//如果有旷工，且不是因为当天离职早走
							if ($date == $staff['quitDay']) {
								$signEndResult .= "-";
							} elseif (($no_work_minute - $holidayMinute) <= $absenteeismMinute) {
								//早退分钟数
								$state = '早退';
							} elseif ($no_work_minute > $holidayMinute) {
								$isOneDayWork = false;
							}
						}
						if (!$isOneDayWork) {
							//是否一天正常上班
							$state = '旷工';
						}
					}
				}
			} elseif ($clockRule['type'] == 2) {
				//班次
				//按班次上下班
				$rosterMx         = query('roster_detail', " id = '$schedule[rosterMxId]'");//班次信息
				$clockTimeMx      = find(array('table' => 'clock_rule_time', 'where' => " orderId = '$rosterMx[id]' order by list asc"));
				$endClockTime     = end($clockTimeMx['array']);
				$morning['start'] = strtotime($date . " " . $clockTimeMx['array'][0]['startTime']);//上午上班时间戳
				
				$sign = $this->workSign(2, $staff['stid'], $date . " " . $clockTimeMx['array'][0]['startTime'], $date . " " . $endClockTime['endTime'], $this->rangeHour);
				//判断下班时间是否是次日
				if ($endClockTime['endType'] == 1) {
					//次日
					$nextDay          = date('Y-m-d', strtotime("+1", strtotime($date)));
					$afternoon['end'] = strtotime($nextDay . " " . $endClockTime['endTime']);//下午下班时间戳
				} else {
					$afternoon['end'] = strtotime($date . " " . $endClockTime['endTime']);//下午下班时间戳
				}
				
				//打卡时间分析
				$signNum = count($sign);                                                           //今天打卡的次数
				$holiday = $this->judgeOneDayLeave($staff['stid'], $date, $clockTimeMx['array']);
				if ($holiday['oneDay']) {
					//全天请假
					$state = '请假';
				} elseif (strtotime($date) >= time()) {//未来时间
					$state = "---";
				} elseif (strtotime($date) < strtotime($staff['entryDay'])) {//今天未入职
					$state = "未入职";
				} elseif ($staff['state'] == "离职" and strtotime($staff['quitDay']) < strtotime($date)) {//今天已离职
					$state = "已离职";
				} elseif ($signNum == 0) {
					$state = '旷工';
				} elseif ($signNum == 1) {
					$signTime  = key($sign);          //唯一打卡时间
					$signStamp = strtotime($signTime);//签到时间戳
					$state     = '旷工';
					$text      = date("H:i:s", strtotime($signTime));
					if ($afternoon['end'] <= $signStamp) {//如果是下班之后打的卡
						$signStartResult = '缺卡';
						$signEndResult   = $text . $holiday['end'] . date('Y-m-d H:i:s', $afternoon['end']);
					} elseif ($signStamp <= $morning['start']) {//如果是上班之前打的卡
						$signStartResult = $text;
						$signEndResult   = '缺卡';
					} elseif ($signStamp <= $morning['start'] + 60 * $absenteeismMinute) {
						$signStartResult = $text;
						$signEndResult   = '缺卡';
					} else {
						//迟到半小时后
						$signStartResult = $text;
						$signEndResult   = '缺卡';
					}
				} else {
					//上班签到时间戳
					$signStartTime  = key($sign);
					$signStartStamp = strtotime($signStartTime);
					//下班签到时间戳
					end($sign);//把指针切换到数组最后一条记录
					$signEndTime  = key($sign);
					$signEndStamp = strtotime($signEndTime);
					//判断
					if ($signEndStamp <= $morning['start']) {//仅在上班前打了两次卡
						$signStartResult = date("H:i:s", strtotime($signStartTime));
						$signEndResult   = '缺卡';
					} elseif ($afternoon['end'] <= $signStartStamp) {//仅在下班后打了两次卡
						$signStartResult = '缺卡';
						$signEndResult   = date("H:i:s", strtotime($signEndTime));
					} else {
						//两次打卡都在上班时间或正常打卡
						$isOneDayWork = true;                                   //判断是否为非旷工的标志
						//上班签到标记
						$signStartResult = date("H:i:s", strtotime($signStartTime));
						if ($signStartStamp > $morning['start']) {
							//有迟到
							//上班签到前缺勤分钟数
							$leaveStart = $this->calculateRemindEarlyHour($date, $signStartStamp, $clockTimeMx['array']);
							//上班签到前的总请假分钟数
							$holidayStart = $this->calculateEarlyHolidayHour($staff['stid'], $date, $signStartStamp, $clockTimeMx['array']);
							if (($leaveStart - $holidayStart) <= $absenteeismMinute) {
								//缺勤分钟数扣除请假分钟数后如果在<=半小时，则属于迟到
								$state = '迟到';
							} elseif ($leaveStart > $holidayStart) {
								//如果有旷工
								$isOneDayWork = false;
							}
						}
						//下班签到标记
						$signEndResult = date("H:i:s", strtotime($signEndTime));//下班签到标记
						if ($afternoon['end'] > $signEndStamp) {
							//有早退
							//当前打卡时间后的缺勤分钟数
							$no_work_minute = $this->calculateRemindWorkHour($date, $signEndStamp, $clockTimeMx['array']);
							//当前打卡时间后的请假分钟数
							$holidayMinute = $this->calculateHolidayHour($staff['stid'], $date, $signEndStamp, $clockTimeMx['array']);
							//如果有旷工，且不是因为当天离职早走
							if ($date == $staff['quitDay']) {
								$signEndResult .= "<span class='green'>离</span>";
							} elseif (($no_work_minute - $holidayMinute) <= $absenteeismMinute) {
								$state = '早退';
							} elseif ($no_work_minute > $holidayMinute) {
								$isOneDayWork = false;
							}
						}
						if (!$isOneDayWork) {
							$state = '旷工';
						}
					}
				}
			} else {
				$signNum = count($sign);//今天打卡的次数
//                $holidaySign = $obj->flex_holiday($date, $staff['stid']);//判断当天是否有请假
				if (strtotime($date) >= time()) {//未来时间
					$state = "---";
				} elseif (strtotime($date) < strtotime($staff['entryDay'])) {//今天未入职
					$state = "未入职";
				} elseif ($staff['state'] == "离职" and strtotime($staff['quitDay']) < strtotime($date)) {//今天已离职
					$state = "已离职";
				} elseif ($signNum == 0) {
					$state = '旷工';
				} elseif ($signNum == 1) {
					$signTime        = key($sign);//唯一打卡时间
					$text            = date("H:i:s", strtotime($signTime));
					$signStartResult = $text;
					$signEndResult   = '缺卡';
				} else {
					//上班签到时间戳
					$signStartTime = key($sign);
					//下班签到时间戳
					end($sign);                                             //把指针切换到数组最后一条记录
					$signEndTime = key($sign);
					//上班签到标记
					$signStartResult = date("H:i:s", strtotime($signStartTime));
					//下班签到标记
					$signEndResult = date("H:i:s", strtotime($signEndTime));//下班签到标记
				}
			}
			return ['startSignTime' => $signStartResult, 'endSignTime' => $signEndResult, 'state' => $state];
		} else {
			return ['startSignTime' => '-', 'endSignTime' => '-', 'state' => ''];
		}
	}
	
	
	/**
	 * 获取一个月的工作天数和数组
	 */
	public function getWorkDay($date, $workDayId): array
	{
		$workDay    = query('work_day', " id = '$workDayId'");
		$workDayArr = [];//工作天数组
		$arr        = $workDay['workDay'] ? json_decode($workDay['workDay'], true) : [];
		foreach ($arr as $val) {
			if (date('Y-m', strtotime($date)) == date('Y-m', strtotime($val))) {
				$workDayArr[] = $val;
			}
		}
		return array('workDay' => $workDayArr, 'dayNum' => count($workDayArr));
	}
	
	/**
	 * 固定班制---早退==计算剩余工作分钟数
	 *
	 * @param $today
	 * @param $signStamp
	 * @param $clockGroupMxAll
	 * @return float|int
	 */
	public function calculateRemindWorkHour($today, $signStamp, $clockGroupMxAll): float|int
	{
		$flag   = false;//是否开始计算
		$minute = 0;
		foreach ($clockGroupMxAll as $val) {
			$workStartTimeStamp = strtotime($today . " " . $val['startTime']);//上班时间戳
			if ($val['endType'] == 1) {
				//判断下班时间是否为次日
				$nextDay          = date('Y-m-d', strtotime("+1", strtotime($today)));
				$workEndTimeStamp = strtotime($nextDay . " " . $val['endTime']);//下班时间戳
			} else {
				$workEndTimeStamp = strtotime($today . " " . $val['endTime']);//下班时间戳
			}
			if ($workEndTimeStamp > $signStamp && !$flag) {
				$flag   = true;//开始计算
				$minute += floor($workEndTimeStamp - $signStamp) / 60;
			} elseif ($flag) {
				$minute += floor($workEndTimeStamp - $workStartTimeStamp) / 60;
			}
		}
		return $minute;
	}
	
	
	/**
	 * 固定制--早退-- 计算请假分钟数
	 *
	 * @param        $stid
	 * @param        $today
	 * @param        $signStamp
	 * @param        $clockGroupMxAll
	 * @param string $where
	 */
	public function calculateHolidayHour($stid, $today, $signStamp, $clockGroupMxAll, $where = '')
	{
		$minute = 0;
		foreach ($clockGroupMxAll as $val) {
			if ($val['endType'] == 1) {
				//判断下班时间是否为次日
				$nextDay          = date('Y-m-d', strtotime("+1", strtotime($today)));
				$workEndTimeStamp = strtotime($nextDay . " " . $val['endTime']);//下班时间戳
				$workEndTime      = $nextDay . " " . $val['endTime'];
			} else {
				$workEndTimeStamp = strtotime($today . " " . $val['endTime']);//下班时间戳
				$workEndTime      = $today . " " . $val['endTime'];
			}
			//判断下班结束时间大于签到时间
			if ($workEndTimeStamp > $signStamp) {
				$all = sqlFind("select * from `work_holiday` where date(startTime)<='$today' {$where} and date(endTime)>='$today' and state = '已通过' and stid = '$stid' order by startTime asc");
				foreach ($all as $item) {
					//判断请假时间段和上班时间段有交集的
					$result = $this->timeBetween($item['startTime'], $item['endTime'], date('Y-m-d H:i:s', $signStamp), $workEndTime);
					if ($result['isBetween']) {
						//有交集
						$minute += $result['minute'];
					}
				}
			}
		}
		return $minute;
	}
	
	
	/**
	 * 判断两个时间段是否存在交集
	 *
	 * @param $aStart
	 * @param $aEnd
	 * @param $bStart
	 * @param $bEnd
	 * @return array true 有交集
	 */
	public function timeBetween($aStart, $aEnd, $bStart, $bEnd): array
	{
		//例子
		$astart         = strtotime($aStart);//第1个开始
		$aend           = strtotime($aEnd);  //第1个结束
		$bstart         = strtotime($bStart);//第2个开始
		$bend           = strtotime($bEnd);  //第2个结束
		$isIntersection = false;
		$minute         = 0;//分钟数
		$cend           = $cstart = 0;
		if ($bstart - $astart > 0) {
			if ($bstart - $aend <= 0) {
				$cstart         = $bstart;
				$cend           = $aend;
				$isIntersection = true;
			}
		} elseif ($bend - $astart > 0) {
			$cstart         = $astart;
			$cend           = $bend;
			$isIntersection = true;
		}
		if ($isIntersection) {
			$minute = floor(($cend - $cstart) / 60);//取分钟数  请假
		}
		return ['isBetween' => $isIntersection, 'minute' => $minute];
	}
	
	/**
	 * 固定制
	 * 签到开始打卡请假分钟数
	 */
	public function calculateEarlyHolidayHour($stid, $today, $signStamp, $clockGroupMxAll, $where = '')
	{
		$minute = 0;
		//请假结束时间大于上班开始时间
		foreach ($clockGroupMxAll as $val) {
			$workStartTimeStamp = strtotime($today . " " . $val['startTime']);//上班时间戳
			if ($val['endType'] == 1) {
				//判断下班时间是否为次日
				$nextDay          = date('Y-m-d', strtotime("+1", strtotime($today)));
				$workEndTimeStamp = strtotime($nextDay . " " . $val['endTime']);//下班时间戳
			} else {
				$workEndTimeStamp = strtotime($today . " " . $val['endTime']);//下班时间戳
			}
			if ($workStartTimeStamp < $signStamp) {
				//上班时间比签到时间小的
				$all = find(array('table' => 'work_holiday', 'where' => " date(startTime)<='$today' {$where} and date(endTime)>='$today' and state = '已通过' and stid = '$stid' order by startTime asc"));
				foreach ($all['array'] as $item) {
					//判断请假时间段和上班时间段有交集的
					$result = $this->timeBetween($item['startTime'], $item['endTime'], $today . " " . $val['startTime'], date('Y-m-d H:i:s', $signStamp));
					if ($result['isBetween']) {
						//有交集
						$minute += $result['minute'];
					}
				}
			}
		}
		return $minute;
	}
	
	/**
	 * 固定制
	 * 签到开始打卡缺勤分钟数
	 */
	public function calculateRemindEarlyHour($today, $signStamp, $clockGroupMxAll)
	{
		$flag   = false;//是否结束计算
		$minute = 0;
		foreach ($clockGroupMxAll as $val) {
			$workStartTimeStamp = strtotime($today . " " . $val['startTime']);//上班时间戳
			if ($val['endType'] == 1) {
				//判断下班时间是否为次日
				$nextDay          = date('Y-m-d', strtotime("+1", strtotime($today)));
				$workEndTimeStamp = strtotime($nextDay . " " . $val['endTime']);//下班时间戳
			} else {
				$workEndTimeStamp = strtotime($today . " " . $val['endTime']);//下班时间戳
			}
			if ($workEndTimeStamp >= $signStamp && !$flag) {
				$minute += floor(($signStamp - $workStartTimeStamp) / 60);
				$flag   = true;//结束计算
			} elseif (!$flag) {
				//整段时间都没打卡
				$minute += floor(($workEndTimeStamp - $workStartTimeStamp) / 60);
			}
		}
		return $minute;
	}
	
	/**
	 * 固定班制--- 判断一整天是否都是请假
	 *
	 * @param $stid
	 * @param $today
	 * @param $clockGroupMxAll
	 * @return array
	 */
	public function judgeOneDayLeave($stid, $today, $clockGroupMxAll): array
	{
		$isAll        = false;
		$holidayTitle = "";//上午和下午请假标记
		//判断当前上班时间是否包含在请假时间中
		foreach ($clockGroupMxAll as $index => $val) {
			$all           = find(array('table' => 'work_holiday', 'where' => " date(startTime)<='$today' and date(endTime)>='$today' and state = '已通过' and stid = '$stid' order by startTime asc"));
			$tempStamp     = 0;
			$isStartTimeIn = false;//上班开始时间是否处于请假区间内状态；
			foreach ($all['array'] as $k => $item) {
				$workStartTimeStamp = strtotime($today . " " . $val['startTime']);//上班时间戳
				if ($val['endType'] == 1) {
					//判断下班时间是否为次日
					$nextDay          = date('Y-m-d', strtotime("+1", strtotime($today)));
					$workEndTimeStamp = strtotime($nextDay . " " . $val['endTime']);//下班时间戳
				} else {
					$workEndTimeStamp = strtotime($today . " " . $val['endTime']);//下班时间戳
				}
				if ($index == 0) {
					//请假标记
					$holidayTitle .= ' ' . $item['text'] . ' ' . $item['startTime'] . '-' . $item['endTime'];
				}
				//先判断从当天上班时间开始是否处于请假时间内
				if ($workStartTimeStamp <= strtotime($item['endTime']) && $workStartTimeStamp >= strtotime($item['startTime'])) {
					$isStartTimeIn = true;
				}
				if ($isStartTimeIn) {
					if ($k == 0 && $workEndTimeStamp > strtotime($item['endTime'])) {
						//下班时间大于请假结束时间
						$tempStamp = strtotime($item['endTime']);
						$isAll     = false;
					} elseif ($k > 0 && $tempStamp > 0 && strtotime($item['endTime']) > $tempStamp && $tempStamp >= strtotime($item['startTime'])) {
						//如果下一次的请假时间没有衔接上  则没满一天；
						$isAll = false;
					} else {
						$isAll = true;
					}
				}
			}
		}
		$text = '';
		if ($holidayTitle) {
			$text = "<span class='green' title='" . $holidayTitle . "'>假</span>";
		}
		return ['oneDay' => $isAll, 'signText' => $text];
	}
	
	/**
	 * 获取打卡记录
	 */
	public function workSign(int $type, string $stid, string $startTime, string $endTime, $hour = 0): array
	{
		$sign = [];
		switch ($type) {
			case 1:
				//固定上下班
				$sql = find(["table" => "work_sign", "where" => " stid = '$stid' and signTime >= '$startTime' and signTime <= '$endTime' order by signTime "]);
				foreach ((array)$sql['array'] as $array) {
					if ($array['type'] == '补卡单') {
						$workSignAdd              = query('work_sign_add', " stid = '$stid' and signTime = '$array[signTime]' and state = '已通过'");
						$sign[$array['signTime']] = array("type" => "补", "text" => $workSignAdd['text']);
					} else {
						$sign[$array['signTime']] = array("type" => $array['type']);
					}
				}
				break;
			case 2:
				//固定班次
				$todayStart = date('Y-m-d H:i:s', strtotime($startTime) - 3600 * $hour);
				$todayEnd   = date('Y-m-d H:i:s', strtotime($endTime) + 3600 * $hour);
				
				$sql = find(array("table" => "work_sign", "where" => " stid = '$stid' and signTime >= '$todayStart' and signTime <= '$todayEnd' order by signTime "));
				foreach ((array)$sql['array'] as $array) {
					if ($array['type'] == '补卡单') {
						$workSignAdd              = query('work_sign_add', " stid = '$stid' and signTime = '$array[signTime]' and state = '已通过'");
						$sign[$array['signTime']] = array("type" => "补", "text" => $workSignAdd['text']);
					} else {
						$sign[$array['signTime']] = array("type" => $array['type']);
					}
				}
				break;
			default:
				# code...
				break;
		}
		return $sign;
	}
	
	
	/*申请*/
	public function apply()
	{
		$this->code         = 1;
		$data['result']     = [
			[
				'name' => '补卡',
				'ico'  => oaIndexAppClass::icon('workSignAdd'),
				'url'  => '../workSignAdd/workSignAdd',
			],
			[
				'name' => '请假',
				'ico'  => oaIndexAppClass::icon('holiday'),
				'url'  => '../workHoliday/workHoliday',
			],
			[
				'name' => '外出',
				'ico'  => oaIndexAppClass::icon('out'),
				'url'  => '../workOut/workOut',
			],
			[
				'name' => '加班',
				'ico'  => oaIndexAppClass::icon('workAdd'),
				'url'  => '../work/work',
			],
		];
		$this->resp['data'] = $data;
	}
}
